////////////////////////////////////////////////////////////////////////////////
//Copyright 2009 Christopher Betancourt
//
//This file is part of PEAQ
//
//PEAQ is free software: you can redistribute it and/or modify it under the 
//terms of the GNU Lesser General Public License as published by the Free 
//Software Foundation, either version 3 of the License, or (at your option) any
//later version.
//
//PEAQ is distributed in the hope that it will be useful, but WITHOUT ANY 
//WARRANTY; without even the implied warranty of MERCHANTABLILTY or FITTNESS FOR
//A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
//details.
//
//You should have received a copy of the GNU Lesser Public License with PEAQ.  
//If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////////////
package gui;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.color.ColorSpace;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.JTableHeader;

import processing.ProcessingParams;
import processing.StatisticsParams;

import extractBlack.*;
import extractColor.ExtractColorModule;
import extractColor.ExtractColorParams;


public class Peaq extends JFrame implements Runnable{
	private JTextField fileName;
	private JButton browseButton;
	private JFileChooser fileChooser;
	static private Peaq instance;
	private GridBagConstraints gblConsts;	
	private JLabel status;
	private JButton goButton;
	private JTextField outDirName;
	private JButton browseOutButton;
	private Thread workThread;
	private JMenu fileMenu;
	private JMenu helpMenu;
	private JCheckBox enableSums;
	private JCheckBox enableText;
	private JCheckBox enableGraphics;
	private JTable blackParamTable;
	private JTable colorParamTable;
	private JPanel blackPanel;
	private JPanel colorPanel;
	private JComboBox modeBox;

	Peaq()
	{
		super("Pattern Extractor and Quantifier");
		gblConsts=new GridBagConstraints();
		fileChooser=new JFileChooser();
		fileName=new JTextField(40);
		fileMenu=new JMenu("File");
		helpMenu=new JMenu("Help");
		populateMenus();
		browseButton=new JButton("Browse");
		browseButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
				if(fileChooser.showDialog(instance, "Open")==JFileChooser.APPROVE_OPTION)
				{
					fileName.setText(fileChooser.getSelectedFile().getAbsolutePath());
					status.setText("Press go to run with this file");
				}
				
			}
		});
		goButton=new JButton("Go");
		goButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
//						processRun(fileName.getText());
				workThread=new Thread(instance);
				workThread.start();
				
			}
		});
		outDirName=new JTextField(40);
		browseOutButton=new JButton("Browse");
		browseOutButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e)
			{
				fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
				if(fileChooser.showDialog(instance, "Open")==JFileChooser.APPROVE_OPTION)
				{
					outDirName.setText(fileChooser.getSelectedFile().getAbsolutePath());
				}
				
			}
		});
		
		enableSums=new JCheckBox("Enable sums file");
		enableText=new JCheckBox("Enable textual output");
		enableGraphics=new JCheckBox("Enable graphical output");
		
		//enable all outputs by default.
		enableSums.setSelected(true);
		enableText.setSelected(true);
		enableGraphics.setSelected(true);
		
		blackPanel=buildBlackParamPanel();
		colorPanel=buildExtractColorParamPanel();
		blackPanel.setVisible(true);
		colorPanel.setVisible(false);
		
		modeBox=new JComboBox();
		modeBox.addItem("Black");
		modeBox.addItem("Color");
		
		modeBox.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				//add some sanity checks to verify that the state of the go 
				//button is correct for the shown table.
				if(((String)modeBox.getSelectedItem()).equals("Black"))
				{
					blackPanel.setVisible(true);
					colorPanel.setVisible(false);
				}
				else
				{
					blackPanel.setVisible(false);
					colorPanel.setVisible(true);
				}
			}
		});
		
		this.setLayout(new GridBagLayout());
		gblConsts.gridx=0;
		gblConsts.gridy=0;
//		this.add(new JLabel("Control File:"),gblConsts);
//		++gblConsts.gridx;
//		this.add(fileName,gblConsts);
//		++gblConsts.gridx;
//		this.add(browseButton,gblConsts);
//		++gblConsts.gridx;
//		this.add(goButton,gblConsts);
		this.add(new JLabel("Extraction Mode:"),gblConsts);
		++gblConsts.gridx;
		this.add(modeBox,gblConsts);
		++gblConsts.gridx;
		this.add(goButton,gblConsts);
		++gblConsts.gridy;
		gblConsts.gridx=0;
		this.add(new JLabel("Output Directory:"),gblConsts);
		++gblConsts.gridx;
		this.add(outDirName,gblConsts);
		++gblConsts.gridx;
		this.add(browseOutButton,gblConsts);
		++gblConsts.gridy;
		gblConsts.gridx=0;
		this.add(enableText,gblConsts);
		++gblConsts.gridx;
		this.add(enableGraphics,gblConsts);
		++gblConsts.gridx;
		this.add(enableSums,gblConsts);
		++gblConsts.gridy;
		gblConsts.gridx=0;
		gblConsts.gridwidth=3;
		this.add(blackPanel,gblConsts);
		++gblConsts.gridy;
		this.add(colorPanel,gblConsts);
		++gblConsts.gridy;
		gblConsts.fill=GridBagConstraints.BOTH;
		status=new JLabel();
		status.setText("Awaiting file name");
		this.add(status,gblConsts);
		this.pack();
		this.setVisible(true);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
	}
	
	private JPanel buildBlackParamPanel()
	{
		JPanel retVal=new JPanel(new GridBagLayout());
		GridBagConstraints layout=new GridBagConstraints();
		JButton addButton=new JButton("Add row");
		JButton removeButton=new JButton("Remove row");
		JButton importButton=new JButton("Import data");
		JButton exportButton=new JButton("Export data");
		
		addButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				((ExtractBlackTableModel)blackParamTable.getModel()).addRow();
				goButton.setEnabled(true);
			}
		});
		
		removeButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				if(((ExtractBlackTableModel)blackParamTable.getModel()).getRowCount()>0 &&
						blackParamTable.getSelectedRow()>=0)
					((ExtractBlackTableModel)blackParamTable.getModel()).removeRow(blackParamTable.getSelectedRow());
				if(((ExtractBlackTableModel)blackParamTable.getModel()).getRowCount()<1)
				{
					goButton.setEnabled(false);
				}
			}
			
		});
		
		exportButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
				if(fileChooser.showDialog(instance, "Export Data Set")==JFileChooser.APPROVE_OPTION)
				{
					try
					{
						ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream(fileChooser.getSelectedFile()));
						os.writeObject((ExtractBlackTableModel)blackParamTable.getModel());
					}
					catch(IOException ioe)
					{
						ioe.printStackTrace();
					}
				}
			}
		});
		
		importButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
				if(fileChooser.showDialog(instance, "Import Data Set")==JFileChooser.APPROVE_OPTION)
				{
					try
					{
						ObjectInputStream is=new ObjectInputStream(new FileInputStream(fileChooser.getSelectedFile()));
						blackParamTable.setModel((ExtractBlackTableModel)is.readObject());
					}
					catch(IOException ioe)
					{
						ioe.printStackTrace();
					} 
					catch (ClassNotFoundException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
				}
			}
		});
		
		layout.gridx=0;
		layout.gridy=0;
		layout.gridwidth=4;
		blackParamTable=new JTable(new ExtractBlackTableModel(),new DefaultTableColumnModel());
		blackParamTable.createDefaultColumnsFromModel();
		retVal.add(new JScrollPane(blackParamTable),layout);
		
		++layout.gridy;
		layout.gridwidth=1;
		retVal.add(addButton,layout);
		++layout.gridx;
		retVal.add(removeButton,layout);
		++layout.gridx;
		retVal.add(importButton,layout);
		++layout.gridx;
		retVal.add(exportButton,layout);
		
		
		return retVal;
	}
	
	private JPanel buildExtractColorParamPanel()
	{
		JPanel retVal=new JPanel(new GridBagLayout());
		GridBagConstraints layout=new GridBagConstraints();
		JButton addRowButton=new JButton("Add Row");
		JButton removeRowButton=new JButton("Remove Row");
		JButton exportButton=new JButton("Export Data");
		JButton importButton=new JButton("Import Data");
		
		//set up the buttons
		addRowButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				((ExtractColorTableModel)colorParamTable.getModel()).addRow();
				goButton.setEnabled(true);
			}
		});
		
		removeRowButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e)
			{
				if(((ExtractColorTableModel)colorParamTable.getModel()).getRowCount()>0 &&
						colorParamTable.getSelectedRow()>=0)
				{
					((ExtractColorTableModel)colorParamTable.getModel()).removeRow(
							colorParamTable.getSelectedRow());
				}
				if(((ExtractColorTableModel)colorParamTable.getModel()).getRowCount()<1)
				{
					goButton.setEnabled(false);
				}
			}
		});
		
		exportButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
				if(fileChooser.showDialog(instance, "Export Data Set")==JFileChooser.APPROVE_OPTION)
				{
					try
					{
						ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream(fileChooser.getSelectedFile()));
						os.writeObject((ExtractColorTableModel)colorParamTable.getModel());
					}
					catch(IOException ioe)
					{
						ioe.printStackTrace();
					}
				}
			}
		});
		
		importButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
				if(fileChooser.showDialog(instance, "Import Data Set")==JFileChooser.APPROVE_OPTION)
				{
					try
					{
						ObjectInputStream is=new ObjectInputStream(new FileInputStream(fileChooser.getSelectedFile()));
						colorParamTable.setModel((ExtractColorTableModel)is.readObject());
					}
					catch(IOException ioe)
					{
						ioe.printStackTrace();
					} 
					catch (ClassNotFoundException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
				}
			}
		});
		
		layout.gridx=0;
		layout.gridy=0;
		layout.gridwidth=4;
		colorParamTable=new JTable(new ExtractColorTableModel(),new DefaultTableColumnModel());
		colorParamTable.createDefaultColumnsFromModel();
		colorParamTable.setDefaultEditor(Color.class, new ColorEditor());
		colorParamTable.setDefaultRenderer(Color.class, new ColorRenderer());
		retVal.add(new JScrollPane(colorParamTable),layout);
		++layout.gridy;
		layout.gridwidth=1;
		retVal.add(addRowButton,layout);
		++layout.gridx;
		retVal.add(removeRowButton,layout);
		++layout.gridx;
		retVal.add(exportButton,layout);
		++layout.gridx;
		retVal.add(importButton,layout);
		
		return retVal;
	}
	
	//removed processRun and processImage, never heard back from Justin, so I'll
	//assume that the new implementation produces the same results on his data.
	
	private void populateMenus()
	{
		JMenuBar menuBar=new JMenuBar();
		JMenuItem menuItem;
		//populate the File menu
		menuItem=new JMenuItem("Exit");
		menuItem.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});
		fileMenu.add(menuItem);
		
		//populate the help menu.
		menuItem=new JMenuItem("About",'A');
		menuItem.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				JOptionPane.showMessageDialog(instance, 
"PEAQ is free software: you can redistribute it and/or modify it under the\n"+
"terms of the GNU Lesser General Public License as published by the Free\n"+
"Software Foundation, either version 3 of the License, or (at your option) any\n"+
"later version.\n\n"+
"PEAQ is distributed in the hope that it will be useful, but WITHOUT ANY\n"+
"WARRANTY; without even the implied warranty of MERCHANTABLILTY or FITTNESS FOR\n" +
"A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more\n"+
"details.\n\n"+
"You should have received a copy of the GNU Lesser Public License with PEAQ.\n"+
"If not, see <http://www.gnu.org/licenses/>.",
						"About PEAQ", 
						JOptionPane.INFORMATION_MESSAGE);
			}
		});
		helpMenu.add(menuItem);
		
		menuBar.add(fileMenu);
		menuBar.add(helpMenu);
		this.setJMenuBar(menuBar);
		
	}
	
	public void run()
	{
		BufferedReader controllIn;
		PrintStream statsFile = null;
		PrintStream gridFile = null;
		PrintStream sumsFile=null;
		int nImages;
		String readLine;
		String [] splitLine;
		BufferedImage img=null;
		Graphics2D imgG2d=null;
		int [][]spots=null;
		int [][]sums=null;
		
		ExtractBlackModule ebModule=new ExtractBlackModule();
		ExtractColorModule ecModule=new ExtractColorModule();
		ProcessingParams params;
		ExtractBlackStatistics stats;
		
		goButton.setEnabled(false);
		enableSums.setEnabled(false);
		enableText.setEnabled(false);
		enableGraphics.setEnabled(false);
		
		if(enableSums.isSelected())
		{
			sums=new int[1][1];
			for(int y=0;y<sums.length;++y)
				for(int x=0;x<sums[y].length;++x)
					sums[y][x]=0;
		}
		try{
			if(outDirName.getText().length()==0)
			{
				sumsFile=enableSums.isSelected()?new PrintStream(new File("sums.txt")):null;
			}
			else
			{
				sumsFile=enableSums.isSelected()?new PrintStream(new File(outDirName.getText()+File.separator+"sums.txt")):null;
			}
		}
		catch(Exception ex)
		{
			JOptionPane.showMessageDialog(instance, ex.getMessage(),"Error",
				JOptionPane.ERROR_MESSAGE);
		}
		
		if(((String)modeBox.getSelectedItem()).equals("Black"))
		{
			ExtractBlackTableModel ebtm=(ExtractBlackTableModel)blackParamTable.getModel();
			for(int i=0;i<ebtm.getRowCount();++i)
			{
				String fileNameTxt=(String)ebtm.getValueAt(i, 0);
				String filePortion=fileNameTxt.substring(fileNameTxt.lastIndexOf(File.separator));
				try{
					img=ImageIO.read(new File(fileNameTxt));
					imgG2d=(Graphics2D)img.getGraphics();
					status.setText("Processing "+filePortion);
					status.repaint();
					if(outDirName.getText().length()==0)
					{
						statsFile=new PrintStream(new File(fileName+".stats.txt"));
						gridFile=enableText.isSelected()?new PrintStream(new File(fileName+".grid.txt")):null;
					}
					else
					{
						statsFile=new PrintStream(new File(outDirName.getText()+File.separator+filePortion+".stats.txt"));
						gridFile=enableText.isSelected()?new PrintStream(new File(outDirName.getText()+File.separator+filePortion+".grid.txt")):null;
					}
				}
				catch(Exception ex)
				{
					JOptionPane.showMessageDialog(instance, ex.getMessage(),"Error",
						JOptionPane.ERROR_MESSAGE);
				}
				//now that we have the image, extract the values
				int xUR=0;
				int yUR=0;
				int xLL=0;
				int yLL=0;
				int pixWidth=0;
				int pixHeight=0;
				double rot=0;
				double stdDevs=0;
				rot=(Double)ebtm.getValueAt(i, 1);
				xLL=(Integer)ebtm.getValueAt(i, 2);
				yLL=(Integer)ebtm.getValueAt(i,3);
				xUR=(Integer)ebtm.getValueAt(i, 4);
				yUR=(Integer)ebtm.getValueAt(i, 5);
				pixWidth=(Integer)ebtm.getValueAt(i,6);
				pixHeight=(Integer)ebtm.getValueAt(i,7);
				stdDevs=(Double)ebtm.getValueAt(i, 8);
				//now that we have the values do some work.  Start by rotating
				imgG2d.rotate(Math.toRadians(rot),img.getWidth()/2.0,img.getHeight()/2.0);
				//and then cropping
				Rectangle cropArea=new Rectangle(xLL,yUR,xUR-xLL,yLL-yUR);
				imgG2d.clip(cropArea);
				//now set up the image that will be processed.
				BufferedImage workImage=new BufferedImage(xUR-xLL,yLL-yUR,BufferedImage.TYPE_INT_RGB);
				Graphics2D workG2d=(Graphics2D) workImage.getGraphics();
				workG2d.drawImage(img, 0, 0, xUR-xLL, yLL-yUR, xLL, yUR, xUR, yLL, null);
				
				//now that the image is ready, we can perform the computations 
				//on it.
				status.setText(filePortion+" computing stats");
				status.repaint();
				stats=(ExtractBlackStatistics)ebModule.getStatistics(workImage,null);
				
				//write the statistics file.  There should be some better 
				//exception handling here.
				int [] histogram=stats.getHistogram();
				
				statsFile.println("Mean: "+((Double)stats.getMean()).toString());
				statsFile.println("StdDev: "+((Double)stats.getStdDev()).toString());
				for(int val=0;val<256;++val)
				{
					statsFile.println(((Double)(val/255.0)).toString()+": "+
							((Integer)histogram[val]).toString());
				}
				
				params=new ExtractBlackParams(pixWidth,pixHeight,stdDevs,stats);
				status.setText(filePortion+" extracting pattern");
				spots=ebModule.extractPattern(workImage, params);
			
				//check to see if this image is bigger than any of the others 
				//processed up to this point.  If it is, then create a larger
				//sums array and copy the current sums starting at 0,0.
				if(enableSums.isSelected())
				{
					if(spots.length>sums.length||spots[0].length>sums[0].length)
					{
						int sumsCpy[][]=new int[spots.length][];
						for(int y=0;y<sumsCpy.length;++y)
						{
							sumsCpy[y]=new int[spots[y].length];
							for(int x=0;x<sumsCpy[y].length;++x)
							{
								if(y<sums.length && x<sums[y].length)
								{
									sumsCpy[y][x]=sums[y][x];
								}
								else
								{
									sumsCpy[y][x]=0;
								}
							}
						}
						sums=sumsCpy;
						sumsCpy=null;
					}
				}
				
				//build the sums, output the text file, and build the output 
				//image and write it.
				status.setText(filePortion+" writing output");
				status.repaint();
				for(int y=0;y<spots.length;++y)
				{
					for(int x=0;x<spots[y].length;++x)
					{
						try{
							if(enableSums.isSelected())
								sums[y][x]+=spots[y][x];
							if(enableText.isSelected())
								gridFile.print(((Integer)spots[y][x]).toString()+" ");
						}
						catch(Exception ex){ ex.printStackTrace();}
					}
					try{
						if(enableText.isSelected())
							gridFile.print("\n");
					}
					catch(Exception ex){ ex.printStackTrace();}
				}
			
				if(enableGraphics.isSelected())
				{
					workImage=ebModule.renderPattern(spots, params);
					try{
						if(outDirName.getText().length()==0) 
							ImageIO.write(workImage, "png", new File(fileNameTxt+"spots.png"));
						else
							ImageIO.write(workImage, "png", new File(outDirName.getText()+File.separator+filePortion+"spots.png"));
					}
					catch(Exception ex)
					{
						
					}
				}
			}
		}
		else
		{
			ExtractColorTableModel ectm=(ExtractColorTableModel)colorParamTable.getModel();
			for(int i=0;i<ectm.getRowCount();++i)
			{
				String fileNameTxt=(String)ectm.getValueAt(i, 0);
				String filePortion=fileNameTxt.substring(fileNameTxt.lastIndexOf(File.separator));
				try{
					img=ImageIO.read(new File(fileNameTxt));
					imgG2d=(Graphics2D)img.getGraphics();
					status.setText("Processing "+filePortion);
					status.repaint();
					if(outDirName.getText().length()==0)
					{
						gridFile=enableText.isSelected()?new PrintStream(new File(fileName+".grid.txt")):null;
					}
					else
					{
						gridFile=enableText.isSelected()?new PrintStream(new File(outDirName.getText()+File.separator+filePortion+".grid.txt")):null;
					}
				}
				catch(Exception ex)
				{
					JOptionPane.showMessageDialog(instance, ex.getMessage(),"Error",
						JOptionPane.ERROR_MESSAGE);
				}
				//now that we have the image, extract the values
				int xUR=0;
				int yUR=0;
				int xLL=0;
				int yLL=0;
				int pixWidth=0;
				int pixHeight=0;
				double rot=0;
				Color target=null;
				Color high=null;
				Color low=null;
				rot=(Double)ectm.getValueAt(i, 1);
				xLL=(Integer)ectm.getValueAt(i, 2);
				yLL=(Integer)ectm.getValueAt(i,3);
				xUR=(Integer)ectm.getValueAt(i, 4);
				yUR=(Integer)ectm.getValueAt(i, 5);
				pixWidth=(Integer)ectm.getValueAt(i,6);
				pixHeight=(Integer)ectm.getValueAt(i,7);
				target=(Color)ectm.getValueAt(i, 8);
				high=(Color)ectm.getValueAt(i, 9);
				low=(Color)ectm.getValueAt(i, 10);
				//now that we have the values do some work.  Start by rotating
				imgG2d.rotate(Math.toRadians(rot),img.getWidth()/2.0,img.getHeight()/2.0);
				//and then cropping
				Rectangle cropArea=new Rectangle(xLL,yUR,xUR-xLL,yLL-yUR);
				imgG2d.clip(cropArea);
				//now set up the image that will be processed.
				BufferedImage workImage=new BufferedImage(xUR-xLL,yLL-yUR,BufferedImage.TYPE_INT_RGB);
				Graphics2D workG2d=(Graphics2D) workImage.getGraphics();
				workG2d.drawImage(img, 0, 0, xUR-xLL, yLL-yUR, xLL, yUR, xUR, yLL, null);
				
				
				
				params=new ExtractColorParams(pixWidth,pixHeight,target,high,low);
				status.setText(filePortion+" extracting pattern");
				spots=ecModule.extractPattern(workImage, params);
			
				//check to see if this image is bigger than any of the others 
				//processed up to this point.  If it is, then create a larger
				//sums array and copy the current sums starting at 0,0.
				if(enableSums.isSelected())
				{
					if(spots.length>sums.length||spots[0].length>sums[0].length)
					{
						int sumsCpy[][]=new int[spots.length][];
						for(int y=0;y<sumsCpy.length;++y)
						{
							sumsCpy[y]=new int[spots[y].length];
							for(int x=0;x<sumsCpy[y].length;++x)
							{
								if(y<sums.length && x<sums[y].length)
								{
									sumsCpy[y][x]=sums[y][x];
								}
								else
								{
									sumsCpy[y][x]=0;
								}
							}
						}
						sums=sumsCpy;
						sumsCpy=null;
					}
				}
				
				//build the sums, output the text file, and build the output 
				//image and write it.
				status.setText(filePortion+" writing output");
				status.repaint();
				for(int y=0;y<spots.length;++y)
				{
					for(int x=0;x<spots[y].length;++x)
					{
						try{
							if(enableSums.isSelected())
								sums[y][x]+=spots[y][x];
							if(enableText.isSelected())
								gridFile.print(((Integer)spots[y][x]).toString()+" ");
						}
						catch(Exception ex){ ex.printStackTrace();}
					}
					try{
						if(enableText.isSelected())
							gridFile.print("\n");
					}
					catch(Exception ex){ ex.printStackTrace();}
				}
			
				if(enableGraphics.isSelected())
				{
					workImage=ecModule.renderPattern(spots, params);
					try{
						if(outDirName.getText().length()==0) 
							ImageIO.write(workImage, "png", new File(fileNameTxt+"spots.png"));
						else
							ImageIO.write(workImage, "png", new File(outDirName.getText()+File.separator+filePortion+"spots.png"));
					}
					catch(Exception ex)
					{
						
					}
				}
			}
		}
				
		
		try
		{
			if(enableSums.isSelected())
			{
				for(int y=0;y<sums.length;++y)
				{
					for(int x=0;x<sums[y].length;++x)
					{
						sumsFile.print(((Integer)sums[y][x]).toString()+" ");
					}
					sumsFile.print("\n");
				}
			}
		}
		catch(Exception ex){ ex.printStackTrace();}
		finally{
			goButton.setEnabled(true);
			enableSums.setEnabled(true);
			enableText.setEnabled(true);
			enableGraphics.setEnabled(true);
		}
		status.setText("Completed processing file");
	}
	
	public static void main(String[] args) {
		instance=new Peaq();
	}

}
